﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace ShopeeWebApi.AmazonBase
{
    public class FormulaFunctions : Dictionary<string, FormulaFunction>
    {
        private FormulaFunction Default;
        public FormulaFunctions()
        {
            //IF(LEN\\(\\w{1,2}\\d\\)>0,1,0)
            Reg("IF(LEN(B4)>0,1,0)", (p, a, rs) => FormulaResult.Create(true, Model.Enum.EnumIsMandatory.NONE));
            //IF(VLOOKUP(requiredAttributePTDMap,MATCH(attributeMapFeedProductType,0)+1,FALSE)>0,1,0)
            Reg("IF(VLOOKUP($B$3,requiredAttributePTDMap,MATCH($A4,attributeMapFeedProductType,0)+1,FALSE)>0,1,0)",
                (p, a, AttributeMapRange) => FormulaResult.Create(VLOOKUPImprove(p, a, AttributeMapRange[AttributeMapTypes.Required]), Model.Enum.EnumIsMandatory.REQUIRED));
            //IF(VLOOKUP(optionalAttributePTDMap,MATCH(attributeMapFeedProductType,0)+1,FALSE)>0,1,0)
            Reg("IF(VLOOKUP($B$3,optionalAttributePTDMap,MATCH($A4,attributeMapFeedProductType,0)+1,FALSE)>0,1,0)",
                (p, a, AttributeMapRange) => FormulaResult.Create(VLOOKUPImprove(p, a, AttributeMapRange[AttributeMapTypes.Optional]), Model.Enum.EnumIsMandatory.OPTIONAL));
            //IF(VLOOKUP(preferredAttributePTDMap,MATCH(attributeMapFeedProductType,0)+1,FALSE)>0,1,0)
            Reg("IF(VLOOKUP($B$3,preferredAttributePTDMap,MATCH($A4,attributeMapFeedProductType,0)+1,FALSE)>0,1,0)",
                (p, a, AttributeMapRange) => FormulaResult.Create(VLOOKUPImprove(p, a, AttributeMapRange[AttributeMapTypes.Preferred]), Model.Enum.EnumIsMandatory.DESIRED));
            //AND(IF(IFERROR(VLOOKUP(requiredAttributePTDMap,MATCH(attributeMapFeedProductType,0)+1,FALSE),0)>0,0,1),IF(IFERROR(VLOOKUP(optionalAttributePTDMap,MATCH(attributeMapFeedProductType,0)+1,FALSE),0)>0,0,1),IF(IFERROR(VLOOKUP(preferredAttributePTDMap,MATCH(attributeMapFeedProductType,0)+1,FALSE),0)>0,0,1),IF(IFERROR(MATCH(attributeMapFeedProductType,0),0)>0,1,0))
            Reg("AND(IF(IFERROR(VLOOKUP($B$3,requiredAttributePTDMap,MATCH($A4,attributeMapFeedProductType,0)+1,FALSE),0)>0,0,1),IF(IFERROR(VLOOKUP($B$3,optionalAttributePTDMap,MATCH($A4,attributeMapFeedProductType,0)+1,FALSE),0)>0,0,1),IF(IFERROR(VLOOKUP($B$3,preferredAttributePTDMap,MATCH($A4,attributeMapFeedProductType,0)+1,FALSE),0)>0,0,1),IF(IFERROR(MATCH($A4,attributeMapFeedProductType,0),0)>0,1,0))",
                (p, a, AttributeMapRange) => FormulaResult.Create(formulaFun(p, a, AttributeMapRange), Model.Enum.EnumIsMandatory.DISABLED));
            //AND(AND((0)),1=1)
            Reg("AND(AND((0)),1=1)", (p, a, AttributeMapRange) => FormulaResult.Empty);//置灰，永不命中
            //IF($BN4<>\"Parent\",0,1)
            //AND(AND(OR(AND(AND(IF(COUNTIF\\(.+\\)>0,FALSE,TRUE)))),A4<>\"\"))
            //AND(AND(OR(AND(OR(OR(NOT(JE4<>\"DEFAULT\"),JE4=\"\")))),A4<>\"\"))
            //AND(AND(OR(AND(AND(IF(COUNTIF\\(.+\\)>0,FALSE,TRUE)),AND(IF(COUNTIF\\(.+\\)>0,FALSE,TRUE)),AND(IF(COUNTIF\\(.+\\)>0,FALSE,TRUE)),AND(IF(COUNTIF\\(.+\\)>0,FALSE,TRUE)),AND(IF(COUNTIF\\(.+\\)>0,FALSE,TRUE)))),A4<>\"\"))
            //AND(AND(OR(AND(OR(OR(NOT(KU4<>\"GHS\"),KU4=\"\")),OR(OR(NOT(KV4<>\"GHS\"),KV4=\"\")),OR(OR(NOT(KW4<>\"GHS\"),KW4=\"\")),OR(OR(NOT(KX4<>\"GHS\"),KX4=\"\")),OR(OR(NOT(KY4<>\"GHS\"),KY4=\"\")))),A4<>\"\"))
            //AND(AND(OR(AND(OR(OR(NOT(KU4<>\"not_applicable\"),KU4=\"\")),OR(OR(NOT(KV4<>\"not_applicable\"),KV4=\"\")),OR(OR(NOT(KW4<>\"not_applicable\"),KW4=\"\")),OR(OR(NOT(KX4<>\"not_applicable\"),KX4=\"\")),OR(OR(NOT(KY4<>\"not_applicable\"),KY4=\"\")))),A4<>\"\"))
            //用于关联其他列无值时置灰
            Default = Reg("OtherRef", (p, a, AttributeMapRange) => FormulaResult.Empty);
        }
        public FormulaFunction Reg(string RuleRaw, FormulaFunction.FuncDEL Func)
        {
            var ff = new FormulaFunction(RuleRaw, Func);
            Add(ff.Hash, ff);
            return ff;
        }
        public FormulaResult Invoke(string ruleRaw, string productType, string attribute, AttributeMapRange attributeMapRange)
        {
            var hash = FormulaFunction.CalcHash(FormulaFunction.ClearRange(ruleRaw));
            return (ContainsKey(hash) ? this[hash] : Default).Invoke(productType, attribute, attributeMapRange);
            //if (TryGetValue(hash, out var ff)) {
            //   return ff.Invoke(productType, attribute, attributeMapRange);
            //}
            //else {
            //   return Default.Invoke(productType, attribute, attributeMapRange);
            //    //var message = $"Rule[{ruleRaw}] has not implemented";
            //    //throw new NotImplementedException();
            //}
        }
        /// <summary>
        /// VLOOKUP(str1,requiredAttributePTDMap,str2,FALSE)
        /// </summary>
        /// <param name="arg"></param>
        /// <param name="range"></param>
        /// <returns></returns>
        public bool VLOOKUPImprove(string productType, string attribute, Dictionary<string, Dictionary<string, bool>> range)
        {
            if (range.TryGetValue(attribute, out var valuePairs))
            {
                if (valuePairs.TryGetValue(productType, out var value))
                {
                    bool val = range[attribute][productType];
                    return val;
                }
            }
            return false;
        }

        //AND(
        //IF(IFERROR(VLOOKUP($B$3,requiredAttributePTDMap,MATCH($A4,attributeMapFeedProductType,0)+1,FALSE),0)>0,0,1),
        //IF(IFERROR(VLOOKUP($B$3,optionalAttributePTDMap,MATCH($A4,attributeMapFeedProductType,0)+1,FALSE),0)>0,0,1),
        //IF(IFERROR(VLOOKUP($B$3,preferredAttributePTDMap,MATCH($A4,attributeMapFeedProductType,0)+1,FALSE),0)>0,0,1),
        //IF(IFERROR(MATCH($A4,attributeMapFeedProductType,0),0)>0,1,0))"
        public bool formulaFun(string productType,  string attribute, AttributeMapRange Range)
        {
            var f1 = VLOOKUP(productType, attribute, Range[AttributeMapTypes.Required]);
            var f2 = VLOOKUP(productType, attribute, Range[AttributeMapTypes.Optional]);
            var f3 = VLOOKUP(productType, attribute, Range[AttributeMapTypes.Preferred]);
            return f1 && f2 && f3;             
        }
        public bool VLOOKUP(string productType,  string attribute,  Dictionary<string, Dictionary<string, bool>> range)
        {
            bool b = false;
            try
            {
                if (range.TryGetValue(attribute, out var valuePairs))
                {
                    if (valuePairs.TryGetValue(productType, out var value))
                    {
                        bool val = range[attribute][productType];
                        b=val;
                    }
                }               
            }
            catch (Exception e)
            {
                b= false;
            }
            return !b;
        }
        // IF(IFERROR(MATCH($A4, attributeMapFeedProductType, 0), 0) > 0, 1, 0)
        public bool match(string productType, string[] range)
        {
            bool b = true;
            int j = 0;
            try
            {
                for (int i = 0; i < range.Count(); i++)
                {
                    if (productType.Equals(range[i]))
                    {
                        j = i;
                        break;
                    }
                }
                return j > 0;
            }
            catch (Exception e)
            {
                return false;
            }
        }
    }
}
